  package com.iaz.tech.tools.ai.neuron.cell;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.iaz.tech.tools.ai.neuron.ability.INeuronAbility;
import com.iaz.tech.tools.ai.neuron.ability.INeuronCreateCommunicateAbility;
import com.iaz.tech.tools.ai.neuron.ability.INeuronProgramAbility;
import com.iaz.tech.tools.ai.neuron.exec.NeuronCodeGeneratorFactory;
import com.iaz.tech.tools.common.utils.FileTools;
import com.iaz.tech.tools.common.utils.UtilTools;
import com.iaz.tech.tools.generator.java.INeuronSourceGenerateAble;
import com.iaz.tech.tools.knowledge.IKnowledgeAble;
import com.iaz.tech.tools.message.IMessageAble;
import com.iaz.tech.tools.message.MESSAGESTATE;
import com.iaz.tech.tools.message.impl.MessageForAnswer;
import com.iaz.tech.tools.message.impl.MessageForAsk;
import com.iaz.tech.tools.message.impl.MessageForState;
import com.iaz.tech.tools.message.impl.MessageForTalk;
import com.iaz.tech.tools.property.IPropertyAble;
import com.iaz.tech.tools.property.impl.ValueProperty;
import com.iaz.tech.tools.property.project.Project;
import com.iaz.tech.tools.uml.IUMLNeuronAble;


import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * 功能性神经元
 * 可以进行处理，模块，用于实现网络化神经元执行
 * 执行工程的任务，并能进行任务合并及处理
 * 
 * 此神经元，仅仅进行代码生产。
 * 动词配送。
 * 
 */
@EqualsAndHashCode(callSuper=false)
@Data
public class NeuronCell extends Neuron implements INeuronProgramAbility, INeuronCreateCommunicateAbility{
	
	/**
     * 日志
     */
	private final static Logger logger = (Logger) LoggerFactory.getLogger(NeuronCell.class);
	
	/**
	 * 神经元负责的Properties, 用于记录
	 * 神经元在执行中，所承担的工程
	 */
	private Map<String, Project> projs = new HashMap<String,Project>();
	/**
	 * 通信包, 用于进行通讯
	 * 不同的工程，不同的联系
	 */
	private Map<String, List<INeuronAbility>> concats = new HashMap<String, List<INeuronAbility>>();
	/**
	 * 自由通信包, 用于进行通讯
	 * 公共的联系方式
	 */
	private List<INeuronAbility> freeConcats = new ArrayList<INeuronAbility>();
	/**
	 * 默认的联系方式
	 */
	private List<INeuronAbility> defaultContacts = new ArrayList<INeuronAbility>();
	/**
	 * 联系方式，用于超远程
	 */
	private List<INeuronAbility> communicateList = new ArrayList<INeuronAbility>();
	/**
	 * 话题，用于神经元进行各种交流。
	 * String 为Project ID 号。
	 */
	private Map<String, List<IMessageAble>> topicTheme = new HashMap<String,List<IMessageAble>>();
	/**
	 * 远程访问
	 */
	private Map<String, NerveCenter> remoteConcats = new HashMap<String, NerveCenter>();
	/**
	 * 此神经元的知识库
	 */
	private IKnowledgeAble knowledges ;
	/**
	 * 神经元use case
	 * 
	 * 用于进行代码生产用的User Case 
	 * 
	 * 利用Package Case 生成代码
	 */
	private IUMLNeuronAble useCase = null;
	
	/**
	 * 创建新的Project
	 */
	private Project generateNewProject(String _project_id) {
		Project result = null;
		try {
			if (UtilTools.IsNull(_project_id)) {
				throw new Exception("入口参数_project_id 为空！");
			}
			result = new Project();
			result.setName(_project_id);			
		} catch(Exception e) {
			logger.error("异常：" + e.getMessage());
			result = null;
		}
		return result;
	}
	/**
	 * 删除Project, 在Project 任务完成后。
	 * @param project
	 * @return
	 */
	private int clearProject(String project) {
		int result = -1;
		try {
			if (UtilTools.IsNull( project)) {
				throw new Exception("入口参数project为空！");
			}
			this.projs.remove(project);			
		}catch(Exception e) {
			logger.error("异常：" + e.getMessage());
			result = -1;
		}
		return result;
	}
	/**
	 * 根据Project id 获得contact
	 * @param projecid
	 * @return
	 */
	private INeuronAbility getContactForProject(String projecId) {
		INeuronAbility result = null;
		try {
			List<INeuronAbility> contacts = this.concats.get(projecId);
			if (contacts == null) {
				throw new Exception("联系失败！"); 
			}

			for (int i = 0 ; i < contacts.size() ; i++) {
				INeuronAbility contact = contacts.get(i);
				if (contact instanceof NerveCenter) { 
					result = contact;
					break;
				}
			}
		}catch(Exception e){
			logger.error("异常：" + e.getMessage());
		}
		return result;
	}
	
	/**
	 * 做Message Project
	 * @param msgs
	 */
	private void messageToProj(List<IMessageAble> msgs){
		try {
			if (msgs == null) {
				throw new Exception("入口参数msgs为空！");
			}

			List<IMessageAble> delete_msgs = new ArrayList<>();

			while (!msgs.isEmpty()) {
				IMessageAble msg = msgs.get( msgs.size() - 1 );
				if (msg == null) {
					logger.error("消息为空，无法进行处理！");
					continue;
				}
				String project_id = UtilTools.Trim(msg.getProjectID());
				if (UtilTools.IsNull(project_id)) {
					logger.error("消息的工程ID空，无法进行处理！");
					continue;
				}
				/* Message 的种类， 提问：主要发出Message 询问， 回答， 闲聊 */	
				if (msg instanceof MessageForAsk) {
					MessageForAsk ask = (MessageForAsk)msg;
					this.messageToProjForAsk(project_id, ask, delete_msgs);				
				} else if (msg instanceof MessageForAnswer) {
					MessageForAnswer answer = (MessageForAnswer)msg;
					this.messageToProjForAnswer(project_id, answer, delete_msgs);
				} else if (msg instanceof MessageForState) {
						
				} else if (msg instanceof MessageForTalk) {
					/* 如何进行处理 */
					MessageForTalk talk_msg = (MessageForTalk)msg;
					/* 发现Talk, 用于进行交流 */
					if (talk_msg.getTalk() == null) {
						logger.error("发现Talk, 但是Talk 为空！");
						continue;
					}
					INeuronSourceGenerateAble generator = NeuronCodeGeneratorFactory.createGenerator(
						this.getRuntime(), this.useCase);
					if (generator == null) {
						logger.error("无法创建用例代码生成器！");
						continue;
					}
					/* 生成代码 */
					String proj_id = UtilTools.Trim(talk_msg.getProjectID());
					if (proj_id == null) {
						logger.error("发现Talk, 但是Project ID 为空！");
						continue;
					}
					Project proj = this.projs.get(proj_id);
					if (proj == null) {
						logger.error("无法找到Project！");
						continue;
					}
					String code_source = generator.generateSourceCode(proj, this.useCase);
					if (UtilTools.IsNull(code_source)) {
						logger.error("无法生成用例代码！");
						continue;
					}
					/*  */
					FileTools.saveFileData("D:/work/Temp/file/text.java", code_source);
				} 				 
			}
			while(!delete_msgs.isEmpty()) {
				IMessageAble msg = delete_msgs.remove(0);
				if (msg == null) {
					continue;
				}
			}
		} catch(Exception e){	
			logger.error("异常：" + e.getMessage());
		}
	}

	/**
	 * 做Message Project
	 * @param msgs
	 */
	private void messageToProjForAsk(String project_id, MessageForAsk ask, List<IMessageAble> delete_msgs){
		try {
			if (UtilTools.IsNull(project_id)) {
				throw new Exception("入口参数project_id为空！");
			}
			if (ask == null) {
				throw new Exception("入口参数ask为空！");
			}
			if (delete_msgs == null ) {
				throw new Exception("入口参数delete_msgs为空！");
			}

			/* 问题， 提问 */					
			if (ask.getAsk() == null) {
				logger.error("问题初夏异常， 消息丢失。。。");
				delete_msgs.add(ask);
				return;
			}

			if (ask.getMessageState() == MESSAGESTATE.FINISH) {
				return;
			}
			/* 1) 是询问, 发出 */
			if (ask.getMessageState() == MESSAGESTATE.NEW) {
				this.sendMessage(project_id, ask);
				return;
			} else if ( ask.getMessageState() == MESSAGESTATE.DEAL) {
				/*2) 如果回答，没有达到目的，则会发出第二，第三 此询问，如果3次询问都没有结论，则更换提问的人 */ 
				if (ask.getCount() >= 3) {
					this.sendMessage(project_id, ask);
					ask.setCount(1);
				} else {
					ask.setCount( ask.getCount() + 1 );
				} 
			} else if (ask.getMessageState() == MESSAGESTATE.ACQUIRE) {
				/* 3) 如果问题得到回答，并并认可，则进行组装，作为成果发出 */
				return;
			}
		} catch(Exception e){
			logger.error("异常：" + e.getMessage());
		}
	}
	
	/**
	 * 做Message Project
	 * @param msgs
	 */
	private void messageToProjForAnswer(String project_id, MessageForAnswer answer, List<IMessageAble> delete_msgs ){
		try {
			if (UtilTools.IsNull(project_id)) {
				throw new Exception("入口参数project_id为空！");
			}
			if (answer == null) {
				throw new Exception("入口参数answer为空！");
			}
			if (delete_msgs == null ) {
				throw new Exception("入口参数delete_msgs为空！");
			}
			if (answer.getMessageState() == MESSAGESTATE.FINISH) { 
				return;
			} 

			if (answer.getAnswer() == null) {
				logger.error("回答初夏异常， 消息丢失。。。");
				delete_msgs.add(answer);
				return;
			}

			if (answer.getHarvest() != null) {
				answer.setMessageState(MESSAGESTATE.FINISH);
				/* 形成，完成  */
				Project proj = projs.get(project_id);
				if (proj == null) {
					return;
				}
				proj.getProjectResult().push(answer.getHarvest());
			}

		} catch(Exception e){
			logger.error("异常：" + e.getMessage());
		}
	}
	/**
	 * 处理Message
	 */
	private void doneMessage() {
		try {
			/*
			 *  读取Message 列表 
			 */
			for (Map.Entry<String, List<IMessageAble>> entry : this.topicTheme.entrySet()) {
				if ( UtilTools.IsNull(entry.getKey()) ) {
					continue;
				}
				List<IMessageAble> msgs = entry.getValue();
				if (msgs == null) {
					continue;
				}
				if (msgs.size() == 0) {
					continue;
				}

				String proj_id = UtilTools.Trim( entry.getKey() );
				if (UtilTools.IsNull(proj_id)) {
					continue;
				}
				if (!this.projs.containsKey(proj_id)) {
					Project _new_project = generateNewProject(proj_id);
					this.projs.put(proj_id, _new_project);
				}
				this.messageToProj(entry.getValue());
			}
		} catch(Exception e) {
			logger.error("异常：" + e.getMessage());
		}
	}
	 
	/**
	 * 用于生成Project
	 */
	private void dealProjects() {
		/* 根据消息，进行刷新Projects列表 */
		if (this.topicTheme == null) {
			this.topicTheme =  new HashMap<String,List<IMessageAble>>();
		}
		/* 根据话题，获得工程 */
		for(Map.Entry<String, List<IMessageAble>> entry : this.topicTheme.entrySet()) {
			if (UtilTools.IsNull(entry.getKey())) {
				continue;
			}
			if (entry.getValue() == null) {
				continue;
			}
			String key_project = UtilTools.Trim(entry.getKey());
			if (!this.projs.containsKey(key_project)) {
				Project _new_project = generateNewProject(key_project);
				this.projs.put(key_project, _new_project);
			}
		}		
	}
	
	/**
	 * 处理工程(整体)
	 */
	public void doneProjects() {
		try {
			/* 根据消息，进行刷新Projects列表 */
			if (this.topicTheme == null) {
				this.topicTheme =  new HashMap<String,List<IMessageAble>>();
			}
			List<String> deletes = new ArrayList<String>();
			
			/* 读取主题和Project的信息, 根据话题进行代码的生产， 通过消息对话来确定 */
			for(Map.Entry<String, List<IMessageAble>> entry : this.topicTheme.entrySet()) {
				if( UtilTools.IsNull(entry.getKey())) {
					continue;
				}
				if (entry.getValue() == null) {
					deletes.add(entry.getKey());
					continue;
				}			
				if (entry.getValue().size() == 0) {
					continue;
				}				
				if (this.projs.containsKey(UtilTools.Trim(entry.getKey()))) {
					Project _current_proj = this.projs.get(UtilTools.Trim(entry.getKey()));
					if (_current_proj == null) {
						continue;
					}
					doneOneProject(_current_proj, entry.getValue());
				}
			}
			/* 删除错误的Project */
			for(int i = 0; i < deletes.size(); i++ ) {
				this.topicTheme.remove(deletes.get(i));
			}
		}catch(Exception e) {
			logger.error("异常信息：" + e.getMessage());
		}
	}
	
	/**
	 * 处理单独工程
	 * 1. 根据UML 的配置，进行生成代码
	 * 2. 根据Message 进行处理
	 * 3. 根据UML 进行代码
	 * 4. 根据Case 进行处理
	 * 5. 根据Project 进行处理
	 */
	private void doneOneProject(Project _proj, List<IMessageAble> msgs) {
		try {
			if (_proj == null) {
				throw new Exception("入口参数_proj 没有指定。");
			}			
			/* 表示初始状态 */
			if (this.useCase == null ) {
				throw new Exception("this.usecase 为空，无法进行代码生成!");
			}			
			if ((msgs == null) || (msgs.size() == 0)) {
				throw new Exception("入口参数msg 为空！");
			}			
			String neuron_name = this.getNeuronName();
			if (UtilTools.IsNull(neuron_name)) {
				throw new Exception("Neuron Name 为空，没有指定！");
			}			
			if (_proj.getProjectResult() == null) {
				/* 判断Prject 是否有成员， 如果没有，则进行处理 */
				// IPropertyAble property = PropertyFactory.createProperty(this.useCase);
				// if (property == null) {
				// 	throw new Exception("本神经元的UseCase 无法转换成Property。 ");
				// }
				// _proj.setProjectResult(property );				
			}			
			for (int i = 0; i < msgs.size(); i++) {
				IMessageAble msg = msgs.get(i);
				if (msg == null) {
					continue;
				}
				_proj.message(msg);
			}
			/* 处理Project, 如果Project 有了结果 */
			if (_proj.getProjectResult() != null) {
				/* 处理Project 结果 */
				if (_proj.isEnd() ) {
					/* 处理Project 结果 */
					this.clearProject(_proj.getProjectID());
				}
			}
		}catch(Exception e) {
			logger.error("异常信息："+ e.getMessage());
			/* 进入休眠 */
			this.setSleepTitle(true);
		}
	}	
	/**
	 * 执行
	 */
	@Override
	public IPropertyAble executeProgram(IPropertyAble _property) {
		try {
			if (_property == null) {
				logger.warn("入口_property 为空。");
			}
			/* 处理Message, 列表 */
			this.doneMessage();
			/* 处理Projects */
			this.dealProjects();
			/* 处理Project */
			this.doneProjects();			
		}catch(Exception e) {
			logger.error("功能性神经元执行异常：" + e.getMessage() );
		}		
		return null;
	}

	/**
	 * 发送消息
	 * @param projid
	 * @param msg
	 */
	private void sendMessage(String projid, IMessageAble msg ) {
		/* 提问， 发送出去 */
		INeuronAbility communication = this.getContactForProject(projid);
		/* 问题 */
		if (communication instanceof NerveCenter) {
			this.talk( ((NerveCenter)communication).getNeuronId(), msg );
		}
		((MessageForAsk)msg).setMessageState(MESSAGESTATE.DEAL);
		((MessageForAsk)msg).setCount( ((MessageForAsk)msg).getCount() + 1 );
	}
 
	/**
	 * 接收消息，用于存储，如果神经元细胞为Sleep 或者Await 则无法接受消息
	 */
	@Override
	public IMessageAble talk(UUID neuronID, IMessageAble message) {
		IMessageAble result = null;
		try {
			if (message == null ) {
				throw new Exception("入口参数message 为空!");
			}			
			/* 判断当前标志 */
			if(this.isSleepTitle()  && (this.getTimeoutForSleep() <= 0)) {
				return result;
			}			
			/* 判断当前是否临时暂停 */
			if(this.isSleepTitle() && (this.getTimeoutForSleep() > 0) ) {
				long time_current = (new java.util.Date()).getTime();
				if( (time_current - this.getSleepTitleTime()) < this.getTimeoutForSleep() ) {
					return result;
				}
			}

			String projectID = message.getProjectID();
			if (UtilTools.IsNull(projectID)) {
				throw new Exception("Project ID 没有设置");
			}			
			if ((this.getRemoteConcats() == null) ||
					(!this.getRemoteConcats().containsKey(UtilTools.Trim(projectID))) ) {
				NerveCenter contact_neuron = new NerveCenter();
				this.getRemoteConcats().put(UtilTools.Trim(projectID), contact_neuron);
				return result;
			}			
			NerveCenter current_project_contact = this.getRemoteConcats().get( UtilTools.Trim(projectID));
			if (current_project_contact == null) {
				throw new Exception("当前工程的Contact 不存在。");
			}			
			current_project_contact.talk(neuronID, message);
		} catch(Exception e) {
			logger.error("");
		}
		return result;
	}

	/**
	 * 接收消息，用于传递消息，对别的神经元说。
	 * @param id
	 * @return
	 */
	@Override
	public List<IMessageAble> answer(UUID id) {
		List<IMessageAble> result = new ArrayList<>();
		try {
			
			UUID neuronID = this.getNeuronId();
			if (neuronID == null) {
				throw new Exception("异常，neuron id 没有指定！");
			}
			/* 判断是否有联系的工程 */
			if (this.getRemoteConcats().size() == 0) {
				return result;
			}
			/* 判断当前标志 */
			if(this.isSleepTitle()  && (this.getTimeoutForSleep() <= 0)) {
				return result;
			}
			/* 判断当前是否临时暂停 */
			if(this.isSleepTitle() && (this.getTimeoutForSleep() > 0) ) {
				long time_current = (new java.util.Date()).getTime();
				if( (time_current - this.getSleepTitleTime()) < this.getTimeoutForSleep() ) {
					return result;
				}
			}			
			for (Map.Entry<String, NerveCenter> _entry : remoteConcats.entrySet()) {
				if (UtilTools.IsNull( _entry.getKey() )) {
					continue;
				}
				if (_entry.getValue() == null) {
					continue;
				}
				
				List<IMessageAble> msgs = _entry.getValue().answer(neuronID);
				if (msgs == null) {
					continue;
				}
				
				//this.messageQueue.addAll(msgs);
			}
			
		} catch(Exception e){
			logger.error("异常信息：" + e.getMessage());
		}
		return result;
	}
	/**
	 * 应用新的通信能力
	 * 1） 根据Project id 进行判断是否有联系的工程
	 * 2） 根据Project id 进行交流
	 * 3） 如果没有工程，则创建一个新的工程
	 */
	@Override
	public INeuronAbility applyNewCommunication() {
		INeuronAbility result = null;
		try {			
			result = new NerveCenter();


			
		} catch(Exception e) {
			logger.error("异常：" + e.getMessage());
		}
		return result;
	}
	/**
	 * 增加通信能力
	 */
	@Override
	public void appendCommunication(INeuronAbility ability) {
		try {			
			if(ability == null) {
				throw new Exception("入口参数ability 为空，没有指定！");
			}
			
			if(this.communicateList == null) {
				this.communicateList = new ArrayList<>();
			}
			
			this.communicateList.add(ability);
			
		} catch(Exception e) {
			logger.error("异常：" + e.getMessage());
		}		
	}	
	
	/* 神经元之间的通信， 1. 直接通信 2. 问题询问 3. 通过第三方进行通信  */
	/**
	 * 内部会话
	 */
	@Override
	public IMessageAble talkMe(IMessageAble message) {
		IMessageAble result = null;
		try {
			if (message == null) {
				throw new Exception("入口参数message 为空，或者没有指定。");
			}
			/* 进行解析，并记录将结果记录的topicTheme中*/
			String message_key = message.getProjectID();
			if ( UtilTools.IsNull(message_key)) {
				throw new Exception("Message key 为空！");
			}			
			List<IMessageAble> messages = null;
			String key = UtilTools.Trim( message_key);
			if (this.topicTheme.containsKey(key)) {
				messages = this.topicTheme.get( key );
			} else {
				messages = new ArrayList<>();
				this.topicTheme.put(key, messages);
			}
			if (messages == null) {
				throw new Exception("message 为空！");
			}
			messages.add(message);
			result = new MessageForTalk();        
			result.setMessage("成功！");
			return result;
		} catch(Exception e) {
			logger.error("出现异常:" + e.getMessage());
		}
		return result;
	}
	
	/**
	 * 执行神经元，是多任务调度用的
	 */
	@Override
	public void execute(Object sender) {
		try {
			System.out.println("执行神经元：" + this.getNeuronId());
			/* 属性 */
			IPropertyAble _property = new ValueProperty();
			IPropertyAble prop_return = this.executeProgram(_property);

			/* 处理Message, 列表 */
			this.doneMessage();
			/* 处理Projects */
			this.dealProjects();
			/* 处理Project */
			this.doneProjects();			

		}catch (Exception e){
			logger.error("出现异常:" + e.getMessage());
		}
	}
	
	@Override
	public void stop() {
		// TODO Auto-generated method stub
		throw new UnsupportedOperationException("Unimplemented method 'stop'");
	}	
}
